%%
%% %CopyrightBegin%
%%
%% Copyright Hillside Technology Ltd. 2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%%     http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% %CopyrightEnd%
%%

%% Note: this file was generated from "example.wsdl" using soap:wsdl2erlang, 
%% but a number of callback functions have been added. 
%% See "soap_server_tutorial.md" for more explanations.

%% generated by soap from: e:/e_soap/soap/doc/example.wsdl
%% for service "contacts_service" and port "contacts_port"
%% using options: [{service,"contacts_service"},{port,"contacts_port"},{generate,both},{namespaces,[{"http://example.com/contacts.xsd",undefined}]},{http_server,soap_server_cowboy_1},{server_name,"example_server"},{http_client,soap_client_ibrowse},{client_name,"example_client"},{strict,true}]

-module(example_server).

-include("example.hrl").

-export([store/3]).
-export([retrieve/3]).
-export([interface/0]).
-export([exception/7]).
-export([init/2]).
-export([header_parser/3]).
-export([header/3]).
-export([check_http_conformance/2]).
-export([protocol_error/3]).

-spec header(Parsed_header::any(), soap:soap_req(), soap:soap_handler_state()) 
  -> {ok, soap:soap_req(), soap:soap_handler_state()}.
header(#'DebuggingHeader'{debugLevel = Level}, Soap_req, State) ->
    {ok, Soap_req, [{debug_level, Level} | State]};
header(#{"credentials" := Credentials}, Soap_req, State) ->
    Authorised = case Credentials of
                 #{"username" := <<"Willem">>, "password" := <<"secret">>} ->
                     true;
                 _ ->
                     false
             end,
    {ok, Soap_req, [{authorised, Authorised} | State]}.

-spec header_parser(Namespace::string(), soap:soap_req(), 
    soap:soap_handler_state()) 
    -> {ok, {fun((Event::erlsom:sax_event(), State::any()) -> any()),
             any()}, soap:soap_req(), soap:soap_handler_state()}.
header_parser("http://example.com/contacts.xsd", Soap_req, S) ->  
    {ok, soap_parsers:data_mapper(soap_interface:model(interface())), Soap_req, S};
header_parser("security", Soap_req, S) ->  
    {ok, soap_parsers:map(), Soap_req, S}.

%%
%% Ensures that the ETS table exists, and links it to the process that 
%% started the server (because otherwise it will disappear between requests).
-spec init(soap:soap_req(), Options::any()) -> 
    {soap:soap_req(), soap:soap_handler_state()}.
init(Soap_req, [Pid]) -> 
    case ets:info(contacts) of
        undefined ->
          ets:new(contacts, [set, named_table, {keypos, #contact.id}, 
                  {heir, Pid, []}, public]);
        _ ->
            ok
    end,
    {Soap_req, []}.

-spec exception(Class::atom(), Reason::any(), Stacktrace::any(),
                soap:soap_fault_code(), Description::string(), soap:soap_req(), 
                soap:soap_handler_state()) -> soap:soap_handler_response(any()).
exception(Class, Reason, Stacktrace, _Type, _Desc, Soap_req, Handler_state) ->
    Message = io_lib:format("exception, class: ~p, reason: ~p,~nstack: ~P~n", 
                            [Class, Reason, Stacktrace, 14]),
    {fault, soap_fault:fault(server, Message, Soap_req), Soap_req, Handler_state}. 

-spec store(Parsed_body::contact(),
    Soap_req::soap:soap_req(), State::soap:soap_handler_state())
    -> soap:soap_handler_response(id()).
store(Parsed_body, Soap_req, State) ->
    Id = ets:info(contacts, size) + 1,
    true = ets:insert(contacts, Parsed_body#contact{id = Id}),
    %% Demonstrate how a Header block can be returned:
    Header = <<"<h:result xmlns:h=\"test\">ok</h:result>">>,
    {ok, #id{id=Id}, [Header], Soap_req, State}.

-spec retrieve(Parsed_body::id(),
    Soap_req::soap:soap_req(), State::soap:soap_handler_state())
    -> soap:soap_handler_response(contact()).
retrieve(#id{id=Id}, Soap_req, State) ->
    case proplists:get_value(debug_level, State, 0) of
        1 ->
            io:format("retrieving contact ~p~n", [Id]);
        _ ->
          ok
    end,
    case proplists:get_value(authorised, State, false) of
        true -> 
            [Contact] = ets:lookup(contacts, Id),
            {ok, Contact, Soap_req, State};
        false ->
            Fault = soap_fault:fault(client, "Not autorised", Soap_req),
            {fault, Fault, Soap_req, State}
    end.

%% Immediately reject requests that use the PUT method with a 405 status code
-spec check_http_conformance(soap:soap_req(), soap:soap_handler_state()) ->  
      soap:soap_handler_response(any()) | 
      {continue, soap:soap_req(), soap:soap_handler_state()}.
check_http_conformance(Soap_req, State) ->  
    case soap_req:method(Soap_req) of
        "PUT" ->
            {error, 405, Soap_req, State};
        _ ->
            {continue, Soap_req, State}
    end.

%% Do not reject requests if the method is "GET" (by default 
%% SOAP 1.1 requests that use GET are rejected).
-spec protocol_error(soap:protocol_error(), soap:soap_req(), 
      soap:soap_handler_state()) -> 
      soap:soap_handler_response(any()) | 
      {continue, soap:soap_req(), soap:soap_handler_state()}.
protocol_error({method_not_allowed, "GET"}, Soap_req, State) ->
    {continue, Soap_req, State}.

%% The 'interface()' function is used by the SOAP framework to access information about
%% the WSDL.
interface() ->
    ?INTERFACE.
